
/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , http = require('http')
  , path = require('path')
  , model = require('./models');

var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
var hash = require('./hash.js').hash;

app.configure(function(){
  app.set('port', process.env.PORT || 80);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'ejs');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser({uploadDir:'./uploads'}));
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
  app.use(express.errorHandler());
});

routes(app);
server.listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});
var userModel = model.userModel;
var courseModel = model.courseModel;
var putQuestionModel = model.putQuestionModel;
var makeTeamModel = model.makeTeamModel;
function getType(o) { 
  var _t; 
  return ((_t = typeof(o)) == "object" ? o==null && "null" || Object.prototype.toString.call(o).slice(8,-1):_t).toLowerCase(); 
}
function diffArray(a,b){
  //求a和b的差异集合,即a-b
  if((getType(a) != 'array')||(getType(b) != 'array')){return null;}
  var aNum = a.length;
  var bNum = b.length;
  if(aNum<bNum){return null;}
  var ret = [];
  var tmp = [];
  for(var i = 0; i < bNum; i++){
    tmp[b[i]] = true;
  }
  for(var i = 0; i < aNum; i++){
    if(!tmp[a[i]]){
      ret.push(a[i]);
    }
  }
  return ret;
}
var pieTime = function(){
  var curTime = new Date();
  var year = curTime.getFullYear();
  var month = curTime.getMonth()+1;
  if(month<10){
    month = '0'+month;
  }
  var date = curTime.getDate();
  if(date<10){
    date = '0'+date;
  }
  var hour = curTime.getHours();
  if(hour<10){
    hour = '0'+hour;
  }
  var minute = curTime.getMinutes();
  if(minute<10){
    minute = '0'+minute;
  }
  var second = curTime.getSeconds();
  if(second<10){
    second = '0'+second;
  }
  var result = year+'-'+month+'-'+date+' '+hour+':'+minute+':'+second;
  return result;
}
Array.prototype.find = function(ele){
  var len = this.length;
  for(var i = len-1; i >= 0; i--){
    if(this[i] == ele){
      return i;
    }
  }
  return -1;
}
function output(data){
  for(var key in data){
    console.log(key+'='+data[key]);
  }
}
io.on('connection',function(socket){
  //为了安全考虑应该在各处验证数据的合法性
  var curAccount = null;   //当前连接对应唯一用户的account
  var curNickname = null; //当前用户的昵称
  var verified = false;  //标记当前连接是否经过验证,若为false不响应任何请求
  var adminAccount = 'dcAdmin100';
  socket.emit('connected');
  socket.on('register',function(data){
    if(verified){return;}
    userModel.findOne({'account':data.account},function(err,user){
      if(err){
        socket.emit('systemError');
        return;
      }
      if(user){
        socket.emit('regError',{
          text:'账号已经被注册'
        });
      }
      else{
        hash(data.password, function(err, salt, hash){
            if(err){
              socket.emit('systemError');
              return;
            }
            var newUser = new userModel({
              'account':data.account,
              'hash': hash,
              'salt': salt,
              'role':1,
              'sex':data.sex,
              'name':data.name,
              'avatar':null,
              'socketId':socket.id
            });
            newUser.save(function(err){
              if(err){
                socket.emit('systemError');
              }
              else{
                verified = true;
                curAccount = newUser.account;
                curNickname = newUser.name;
                socket.emit('loginSuccess',newUser);
              }
            })
        });
      }
    });
  });
  socket.on('login',function(data){
    if(verified){return;}
    userModel.findOne({'account':data.account},function(err,user){
      if(err){
        socket.emit('systemError');
        return;
      }
      if(user){
        hash(data.password, user.salt, function (err, hash) {
          if (err) {
            socket.emit('systemError');
            return;
          }
          if (hash == user.hash) {
            verified = true;
            if(user.socketId){
              var lastSocket = io.sockets.sockets[user.socketId];
              if(lastSocket){
                lastSocket.emit('dump');
              }
            }
            user.socketId = socket.id;
            user.save(function(err){
              if(!err){
                curAccount = user.account;
                curNickname = user.name;
                socket.emit('loginSuccess',user);
              }
            })
          }
          else{
            socket.emit('loginError',{
              text:'密码不正确'
            });
          }
        });
      }
      else{
        socket.emit('loginError',{
          text:'账号不存在'
        });
      }
    });
  });
  socket.on('admin',function(){
    verified = true;
    curAccount = adminAccount;
  });
  socket.on('changeName',function(data){
    if(!verified){return;}
    userModel.findOne({'account':curAccount},function(err,user){
      if(user){
        user.name = data.newName;
        user.save(function(err){
          if(!err){
            socket.emit('changeInfoSuccess',user);
          }
        })
      }
      else{
        socket.emit('changeInfoError');
      }
    });
  });
  socket.on('getTargetInfo',function(data){
    userModel.find({account: {$in: data}},function(err,users){
      if(err){
        socket.emit('systemError');
      }
      else{
        var infos = [];
        var len = users.length;
        for(var i = 0; i < len; i++){
          infos.push({
            account:users[i].account,
            name:users[i].name
          });
        }
        socket.emit('targetInfo',infos);
      }
    })
  });
  socket.on('getQuestionList',function(data){
    if(!verified){return;}
    putQuestionModel.find(function(err,questionList){
      if(err){
        socket.emit('systemError');
      }
      else{
        questionList.sort(function(a,b){
          return b.time-a.time;
        });
        socket.emit('questionList',questionList);
      }
    });
  });
  socket.on('submitPutQuestion',function(data){
    if(!verified||curAccount != adminAccount){return;}
    var newChoice = [];
    for(var i = 0; i < data.array.length; i++){
      newChoice.push({
        flag:data.flag[i],
        text:data.array[i],
        students:[]
      })
    }
    var newQuestion = new putQuestionModel({
      title:data.title,
      choices:newChoice,
      finished:false,
      allStudents:[],
      time:Math.floor(new Date().getTime())
    });
    newQuestion.save(function(err){
      if(err){
        socket.emit('systemError');
      }
      else{
        socket.emit('submitPutQuestionSuccess');
      }
    })
  });
  socket.on('stopQuestion',function(data){
    if(!verified||curAccount != adminAccount){return;}
    putQuestionModel.findOne({'_id':data._id},function(err,question){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(question){
          question.finished = true;
          question.save(function(err){
            if(err){
              socket.emit('systemError');
            }
            else{
              socket.emit('stopQuestionSuccess',question);
            }
          });
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('restartQuestion',function(data){
    if(!verified||curAccount != adminAccount){return;}
    putQuestionModel.findOne({'_id':data._id},function(err,question){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(question){
          question.allStudents = [];
          question.finished = false;
          var cNum = question.choices.length;
          for(var i = 0; i < cNum; i++){
            question.choices[i].students = [];
          }
          question.save(function(err){
            if(err){
              socket.emit('systemError');
            }
            else{
              socket.emit('restartQuestionSuccess',question);
            }
          });
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('restartMakeTeam',function(data){
    if(!verified||curAccount != adminAccount){return;}
    makeTeamModel.findOne({'_id':data._id},function(err,makeTeam){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(makeTeam){
          makeTeam.allStudents = [];
          makeTeam.finished = false;
          var cNum = makeTeam.choices.length;
          for(var i = 0; i < cNum; i++){
            makeTeam.choices[i].groups = [];
          }
          makeTeam.save(function(err){
            if(err){
              socket.emit('systemError');
            }
            else{
              socket.emit('restartMakeTeamSuccess',makeTeam);
            }
          });
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('submitMakeTeam',function(data){
    if(!verified||curAccount != adminAccount){return;}
    var newMakeTeam = new makeTeamModel({
      title:data.title,
      choices:data.array,
      allStudents:[],
      finished:false,
      time:Math.floor(new Date().getTime())
    });
    newMakeTeam.save(function(err){
      if(err){
        socket.emit('systemError');
      }
      else{
        socket.emit('submitMakeTeamSuccess');
      }
    })
  });
  socket.on('refreshMakeTeam',function(data){
    if(!verified){return;}
    makeTeamModel.findOne({'_id':data._id},function(err,makeTeam){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(makeTeam){
          socket.emit('makeTeamInfo',makeTeam)
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('stopMakeTeam',function(data){
    if(!verified||curAccount != adminAccount){return;}
    makeTeamModel.findOne({'_id':data._id},function(err,makeTeam){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(makeTeam){
          //这里实现组队重排的功能
          var okArray = [];
          var choiceNum = makeTeam.choices.length;
          for(var i = 0; i < choiceNum; i++){
            var groupNum = makeTeam.choices[i].groups.length;
            for(var j = 0; j < groupNum; j++){
              okArray = okArray.concat(makeTeam.choices[i].groups[j].students);
            }
          }
          var leftArray = diffArray(makeTeam.allStudents,okArray);
          if(!leftArray){console.log('error');return;}
          var leftNum = leftArray.length;
          console.log('leftNum:'+leftNum);
          //先组建新的队伍
          for(var i = 0; i < choiceNum&&leftNum>0; i++){
            var groupNum = makeTeam.choices[i].groups.length;
            console.log('groupNum:'+groupNum);
            var leftGroupNum = makeTeam.choices[i].maxGroupNum-groupNum;
            console.log('leftGroupNum:'+leftGroupNum);
            var min = makeTeam.choices[i].minStudentNum;
            var max = makeTeam.choices[i].maxStudentNum;
            for(var j = 0; j < leftGroupNum&&leftNum>min; j++){
              var newGroup = {
                students:[]
              };
              for(var k = 0; k < max&&leftNum>0; k++){
                newGroup.students.push(leftArray[--leftNum]);
              }
              console.log(newGroup);
              makeTeam.choices[i].groups.push(newGroup);
            }
          }
          //然后再把未组满的队伍补满
          for(var i = 0; i < choiceNum&&leftNum>0; i++){
            var groupNum = makeTeam.choices[i].groups.length;
            console.log('groupNum:'+groupNum);
            for(var j = 0; j < groupNum&&leftNum>0; j++){
              var gLength = makeTeam.choices[i].groups[j].students.length;
              for(var k = gLength; k < makeTeam.choices[i].maxStudentNum&&leftNum>0; k++){
                makeTeam.choices[i].groups[j].students.push(leftArray[--leftNum]);
              }
            }
          }
          makeTeam.finished = true;
          makeTeam.save(function(err){
            if(err){
              socket.emit('systemError');
            }
            else{
              socket.emit('makeTeamFinished',makeTeam);
              userModel.find({account:{$in:makeTeam.allStudents}},function(err,users){
                if(err){
                  socket.emit('systemError');
                }
                else{
                  var uNum = users.length;
                  for(var i = 0; i < uNum; i++){
                    var uc = users[i].socketId;
                    if(uc){
                      var tmp = io.sockets.sockets[uc];
                      if(tmp){
                        tmp.emit('makeTeamFinished',makeTeam);
                      }
                    }
                  }
                }
              })
            }
          })
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('doQuestion',function(data){
    if(!verified){return;}
    putQuestionModel.findOne({'_id':data._id},function(err,question){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(question){
          if(question.allStudents.find(curAccount)>=0){
            socket.emit('doQuestionRepeat');
              return;
          }
          question.allStudents.push(curAccount);
          var ucNum = data.choiceArray.length;
          for(var i = 0; i < ucNum; i++){
            question.choices[data.choiceArray[i]].students.push(curAccount);
          }
          question.save(function(err){
            if(err){
              socket.emit('systemError');
            }
            else{
              socket.emit('doQuestionSuccess',question);
            }
          });
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('refreshChoices',function(data){
    if(!verified){return;}
    putQuestionModel.findOne({'_id':data._id},function(err,question){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(question){
          socket.emit('refreshChoicesSuccess',question);
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('getTeamList',function(data){
    if(!verified){return;}
    makeTeamModel.find(function(err,teamList){
      if(err){
        socket.emit('systemError');
      }
      else{
        teamList.sort(function(a,b){
          return b.time-a.time;
        });
        socket.emit('teamList',teamList);
      }
    });
  });
  socket.on('doSignUp',function(data){
    if(!verified){return;}
    makeTeamModel.findOne({'_id':data._id},function(err,makeTeam){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(makeTeam){
          var already = makeTeam.allStudents.find(curAccount);
          if(already>=0){
            socket.emit('signUpRepeat');
          }
          else{
            makeTeam.allStudents.push(curAccount);
            makeTeam.save(function(err){
              if(err){
                socket.emit('systemError');
              }
              else{
                socket.emit('signUpSuccess',makeTeam);
              }
            })
          }
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('createGroup',function(data){
    if(!verified){return;}
    makeTeamModel.findOne({'_id':data._id},function(err,makeTeam){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(makeTeam){
          var cNum = makeTeam.choices.length;
          if(data.choiceId<0||data.choiceId>=cNum){
            socket.emit('systemError');
          }
          else{
            var allGroup = makeTeam.choices[data.choiceId].groups;
            var gNum = allGroup.length;
            if(gNum >= makeTeam.choices[data.choiceId].maxGroupNum){
              socket.emit('createGroupError',{
                message:'当前选项队伍数已满'
              });
              return;
            }
            var allChoices = makeTeam.choices;
            var cNum = allChoices.length;
            for(var j = 0; j < cNum; j++){
              allGroup = allChoices[j].groups;
              gNum = allGroup.length;
              for(var i = 0; i < gNum; i++){
                var exist = allGroup[i].students.find(curAccount);
                if(exist>=0){
                  socket.emit('createGroupError',{
                    message:'你已在队伍中了，你是黑客吧？'
                  });
                  return;
                }
              }
            }
            makeTeam.choices[data.choiceId].groups.push({
              students:[curAccount]
            });
            makeTeam.save(function(err){
              if(err){
                socket.emit('systemError');
              }
              else{
                socket.emit('createGroupSuccess',makeTeam);
              }
            })
          }
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('joinGroup',function(data){
    if(!verified){return;}
    makeTeamModel.findOne({'_id':data._id},function(err,makeTeam){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(makeTeam){
          var cNum = makeTeam.choices.length;
          if(data.choiceId<0||data.choiceId>=cNum){
            socket.emit('systemError');
          }
          else{
            var allGroup = makeTeam.choices[data.choiceId].groups;
            var gNum = allGroup.length;
            var gIndex = -1;
            for(var i = 0; i < gNum; i++){
              var exist = allGroup[i].students.find(curAccount);
              if(exist>=0){
                socket.emit('makeJoinRequestError',{
                  message:'你已在队伍中了，你是黑客吧？'
                });
                return;
              }
              if(allGroup[i]._id == data.groupId){
                gIndex = i;
              }
            }
            if(gIndex<0){
              socket.emit('systemError');
            }
            else{
              if(allGroup[gIndex].students.length>=makeTeam.choices[data.choiceId].maxStudentNum){
                socket.emit('makeJoinRequestError',{
                  message:'该队伍人数已达上限'
                });
                return;
              }
              userModel.findOne({account:allGroup[gIndex].students[0]},function(err,leader){
                if(err){
                  socket.emit('systemError');
                }
                else{
                  if(!leader){
                    socket.emit('systemError');
                  }
                  else{
                    if(leader.socketId){
                      var leaderSocket = io.sockets.sockets[leader.socketId];
                      if(leaderSocket){
                        socket.emit('makeJoinRequestSuccess');
                        leaderSocket.emit('joinRequest',{
                          requestAccount:curAccount,
                          requestNickname:curNickname,
                          makeTeamId:makeTeam._id,
                          makeTeamTitle:makeTeam.title,
                          choiceId:data.choiceId,
                          choiceText:makeTeam.choices[data.choiceId].text
                        });
                      }
                      else{
                        socket.emit('makeJoinRequestError',{
                          message:'该队长不在线'
                        });
                      }
                    }
                    else{
                      socket.emit('makeJoinRequestError',{
                        message:'该队长不在线'
                      });
                    }
                  }
                }
              })
            }
          }
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('agreeJoinRequest',function(data){
    if(!verified){return;}
    makeTeamModel.findOne({'_id':data.makeTeamId},function(err,makeTeam){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(makeTeam){
          var cNum = makeTeam.choices.length;
          if(data.choiceId<0||data.choiceId>=cNum){
            socket.emit('systemError');
          }
          else{
            var allGroup = makeTeam.choices[data.choiceId].groups;
            var gNum = allGroup.length;
            var gIndex = -1;
            for(var i = 0; i < gNum; i++){
              if(allGroup[i].students[0] == curAccount){
                gIndex = i;
                break;
              }
            }
            if(gIndex<0){
              socket.emit('systemError');
            }
            else{
              if(allGroup[gIndex].students.length>=makeTeam.choices[data.choiceId].maxStudentNum){
                socket.emit('acceptJoinRequestError',{
                  message:'队伍人数已达上限'
                });
                userModel.findOne({account:data.requestAccount},function(err,request){
                  if(!err&&request&&request.socketId){
                    var requestSocket = io.sockets.sockets[request.socketId];
                    if(requestSocket){
                      requestSocket.emit('joinRequestFailed',{
                        message:curNickname+'的队伍人数已达上限'
                      });
                    }
                  }
                })
              }
              else{
                allGroup[gIndex].students.push(data.requestAccount);
                makeTeam.save(function(err){
                  if(!err){
                    socket.emit('makeTeamInfo',makeTeam);
                    userModel.findOne({account:data.requestAccount},function(err,request){
                      if(!err&&request&&request.socketId){
                        var requestSocket = io.sockets.sockets[request.socketId];
                        if(requestSocket){
                          requestSocket.emit('joinRequestAccepted',{
                            message:curNickname+'同意了你的组队申请',
                            makeTeamInfo:makeTeam
                          });
                        }
                      }
                    })
                  }
                })
              }
            }
          }
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('dissolveGroup',function(data){
    if(!verified){return;}
    makeTeamModel.findOne({'_id':data._id},function(err,makeTeam){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(makeTeam){
          var allChoices = makeTeam.choices;
          var cNum = allChoices.length;
          for(var i = 0; i < cNum; i++){
            var allGroup = allChoices[i].groups;
            var gNum = allGroup.length;
            for(var j = 0; j < gNum; j++){
              if(allGroup[j].students[0] == curAccount){
                var members = allGroup[j].students.slice(1);
                allGroup = allGroup.slice(0,j).concat(allGroup.slice(j+1));
                makeTeam.choices[i].groups = allGroup;
                makeTeam.save(function(err){
                  if(err){
                    socket.emit('systemError');
                  }
                  else{
                    socket.emit('groupDissolved',makeTeam);
                    userModel.find({account:{$in:members}},function(err,users){
                      if(err){
                        socket.emit('systemError');
                      }
                      else{
                        var uNum = users.length;
                        for(var i = 0; i < uNum; i++){
                          var uc = users[i].socketId;
                          if(uc){
                            var tmp = io.sockets.sockets[uc];
                            if(tmp){
                              tmp.emit('groupDissolved',makeTeam);
                            }
                          }
                        }
                      }
                    })
                  }
                });
                return;
              }
            }
          }
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('exitGroup',function(data){
    if(!verified){return;}
    makeTeamModel.findOne({'_id':data._id},function(err,makeTeam){
      if(err){
        socket.emit('systemError');
      }
      else{
        if(makeTeam){
          var allChoices = makeTeam.choices;
          var cNum = allChoices.length;
          for(var i = 0; i < cNum; i++){
            var allGroup = allChoices[i].groups;
            var gNum = allGroup.length;
            for(var j = 0; j < gNum; j++){
              var members = allGroup[j].students;
              var exist = members.find(curAccount);
              if(exist>0){
                members = members.slice(0,exist).concat(members.slice(exist+1));
                makeTeam.choices[i].groups[j].students = members;
                makeTeam.save(function(err){
                  if(err){
                    socket.emit('systemError');
                  }
                  else{
                    socket.emit('exitGroupSuccess',makeTeam);
                    userModel.find({account:{$in:members}},function(err,users){
                      if(err){
                        socket.emit('systemError');
                      }
                      else{
                        var uNum = users.length;
                        for(var i = 0; i < uNum; i++){
                          var uc = users[i].socketId;
                          if(uc){
                            var tmp = io.sockets.sockets[uc];
                            if(tmp){
                              tmp.emit('memberExit',{
                                message:curNickname+'退出了您在'+makeTeam.title+'中队伍',
                                info:makeTeam
                              });
                            }
                          }
                        }
                      }
                    })
                  }
                });
                return;
              }
            }
          }
        }
        else{
          socket.emit('systemError');
        }
      }
    });
  });
  socket.on('disconnect',function(){
    if(!verified){return;}
    userModel.findOne({'account':curAccount},function(err,user){
      if(err){
        socket.emit('systemError');
        return;
      }
      if(user){
        verified = false;
        if(socket.id == user.socketId){
          user.socketId = null;
          user.save();
        }
      }
    });
  });
});